#include "PlotWidget.h"
#include "ui_PlotWidget.h"

#include <QFileDialog>
#include <QMessageBox>
#include <QSettings>
#include <MMM/FactoryPluginLoader.h>
#include <MMM/Motion/MotionReaderXML.h>

#include "../common/HandleMotionsWithoutModel.h"

PlotWidget::PlotWidget(QWidget *parent, const std::vector<std::string> &sensorPluginPaths, bool standalone) :
    QWidget(parent),
    ui(new Ui::PlotWidget),
    standalone(standalone),
    currentTimestep(0.0)
{
    ui->setupUi(this);

    motionReader = MMM::MotionReaderXMLPtr(new MMM::MotionReaderXML(sensorPluginPaths));
    motionReader->handleMissingModelFilePath = handleMissingModelFilePath;

    connect(ui->ChoosePlotType, SIGNAL(currentIndexChanged(QString)), this, SLOT(plotTypeChanged(QString)));
    connect(ui->NewPlotButton, SIGNAL(pressed()), this, SLOT(newPlot()));
    connect(ui->LoadAddMotionButton, SIGNAL(pressed()), this, SLOT(loadAdditionalMotions()));

    if (standalone) {
        factoryPluginLoader = boost::shared_ptr<MMM::FactoryPluginLoader<MMM::SensorPlotFactory> >(new MMM::FactoryPluginLoader<MMM::SensorPlotFactory>(SENSOR_PLOT_PLUGIN_LIB_DIR));
        update(factoryPluginLoader->getFactories());
    }

    ui->PlotTabWidget->clear();
}

void PlotWidget::plotTypeChanged(QString type) {
    std::string name = type.toStdString();
    int count = 2;
    while(plotNames.find(name) != plotNames.end()) {
        name = type.toStdString() + std::to_string(count);
        count++;
    }
    ui->ChoosePlotName->setText(QString::fromStdString(name));
}

void PlotWidget::newPlot() {
    QString name = ui->ChoosePlotName->text();
    SinglePlotWidget* plotWidget = new SinglePlotWidget(factories[ui->ChoosePlotType->currentText().toStdString()], name.toStdString(), this, standalone);
    plotWidgets.push_back(plotWidget);
    for (const auto &m : motions) {
        for (SinglePlotWidget* plotWidget : plotWidgets) {
            plotWidget->update(m.first, m.second);
        }
    }
    connect(ui->PlotTabWidget, SIGNAL(currentChanged(int)), this, SLOT(plotTabChanged()));
    connect(plotWidget, SIGNAL(showMessage(const std::string &)), this, SIGNAL(showMessage(const std::string &)));
    connect(plotWidget, SIGNAL(openMotions(MMM::MotionList)), this, SIGNAL(openMotions(MMM::MotionList)));
    connect(plotWidget, SIGNAL(jumpTo(float)), this, SIGNAL(jumpTo(float)));
    ui->PlotTabWidget->addTab(plotWidget, name);
    ui->PlotTabWidget->setCurrentWidget(plotWidget);
    currentPlotWidget = plotWidget;
    plotNames.insert(name.toStdString());
    plotTypeChanged(ui->ChoosePlotType->currentText());
}

void PlotWidget::loadAdditionalMotions() {
    QStringList qMotionFilePaths = QFileDialog::getOpenFileNames(this, tr("Open motion"), "", tr("Motion files (*.xml)"));
    if (qMotionFilePaths.size() > 0) {
        std::vector<std::string> motionFilePaths;
        for (QString m : qMotionFilePaths) motionFilePaths.push_back(m.toStdString());
        loadMotions(motionFilePaths);
    }
}

void PlotWidget::loadMotions(const std::vector<std::string> &motionFilePaths) {
    for (const std::string &motionFilePath : motionFilePaths) {
        try {
            MMM::MotionList motions = motionReader->loadAllMotions(motionFilePath);
            for (SinglePlotWidget* plotWidget : plotWidgets) {
                plotWidget->update(motionFilePath, motions);
            }
            this->motions[motionFilePath] = motions;
        } catch (MMM::Exception::MMMException &e) {
            QMessageBox* msgBox = new QMessageBox(this);
            std::string message = "Could not open motion '" + motionFilePath + "'! " + e.what();
            msgBox->setText(QString::fromStdString(message));
            MMM_ERROR << message << std::endl;
            msgBox->exec();
        }
    }
}

void PlotWidget::loadMotions(MMM::MotionList motions) {
    if (motions.size() == 0) return;
    std::string motionFilePath = motions[0]->getOriginFilePath();
    for (SinglePlotWidget* plotWidget : plotWidgets) {
        plotWidget->update(motionFilePath, motions);
    }
    this->motions[motionFilePath] = motions;
}

void PlotWidget::addImportButton(QPushButton* button) {
    ui->loadMotionLayout->addWidget(button);
}

PlotWidget::~PlotWidget()
{
    delete ui;
}

void PlotWidget::update(std::map<std::string, MMM::SensorPlotFactoryPtr> sensorPlotFactories) {
    this->factories = sensorPlotFactories;
    ui->ChoosePlotType->clear();
    for (const auto &f : factories) {
        ui->ChoosePlotType->addItem(QString::fromStdString(f.first));
    }
    for (SinglePlotWidget* widget : plotWidgets) {
        if (this->factories.find(widget->getPlotFactory()->getName()) == this->factories.end())
            ui->PlotTabWidget->removeTab(ui->PlotTabWidget->indexOf(widget));
    }
}

void PlotWidget::plotTabChanged() {
    currentPlotWidget = ((SinglePlotWidget*) ui->PlotTabWidget->currentWidget());
    currentPlotWidget->moveSlider(currentTimestep);
}

void PlotWidget::moveSlider(float timestep) {
    currentTimestep = timestep;
    currentPlotWidget->moveSlider(timestep);
}

    boost::shared_ptr<MMM::FactoryPluginLoader<MMM::SensorPlotFactory> > PlotWidget::getFactoryLoader() {
    return factoryPluginLoader;
}
